home *** CD-ROM | disk | FTP | other *** search
- /* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file
- **
- ** Copyright (C) 1989 by Jef Poskanzer.
- ** Modified 20/Jun/93 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
- ** - 24bit support (new options -24if, -24force)
- ** - HAM8 support (well, anything from HAM3 to HAM(MAXPLANES))
- ** - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes)
- ** - colormap file (new option -map)
- ** - write colormap only (new option -cmaponly)
- ** - only writes CAMG chunk if its a HAM-picture
- ** Modified 29/Aug/93 by Ingo Wilken
- ** - operates row-by-row whenever possible
- ** - faster colorscaling with lookup-table (~20% faster on HAM pictures)
- ** - options -ham8 and -ham6 now imply -hamforce
- **
- **
- ** std HAM 24bit cmap direct
- ** -------+-----+-----+-----+-----+-----
- ** BMHD yes yes yes yes yes
- ** CMAP yes (1) no yes no
- ** BODY yes yes yes no yes
- ** other - CAMG - - DCOL
- ** nPlanes 1-8 3-8 24 0 3-24 if configured without ILBM_BIGRAW
- ** nPlanes 1-16 3-16 24 0 3-48 if configured with ILBM_BIGRAW
- **
- ** (1): grayscale colormap
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- */
-
- #include "ppm.h"
- #include "ppmcmap.h"
- #include "ilbm.h"
-
-
- #define MODE_DIRECT 4 /* direct color ILBM */
- #define MODE_CMAP 3 /* write normal file, but colormap only */
- #define MODE_24 2 /* write a 24bit (deep) ILBM */
- #define MODE_HAM 1 /* write a HAM */
- #define MODE_NONE 0 /* write a normal picture */
-
- #define ECS_MAXPLANES 5
- #define ECS_HAMPLANES 6
- #define AGA_MAXPLANES 8
- #define AGA_HAMPLANES 8
-
- #ifdef AMIGA_AGA
- #define DEF_MAXPLANES AGA_MAXPLANES
- #define DEF_HAMPLANES AGA_HAMPLANES
- #else
- #define DEF_MAXPLANES ECS_MAXPLANES
- #define DEF_HAMPLANES ECS_HAMPLANES
- #endif
- #define DEF_DCOLPLANES 5
-
-
- static int colorstobpp ARGS((int colors));
- #define put_fourchars(str) (void)(fputs(str, stdout))
- static void put_big_short ARGS((short s));
- static void put_big_long ARGS((long l));
- #define put_byte(b) (void)(putc((unsigned char)(b), stdout))
- static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, int hambits));
- static void ppm_to_24 ARGS((FILE *fp, int cols, int rows, int maxval));
- static void ppm_to_direct ARGS((FILE *fp, int cols, int rows, int maxval, DirectColor *direct));
- static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, colorhist_vector chv, int colors, int nPlanes));
- static void ppm_to_cmap ARGS((int maxval, colorhist_vector chv, int colors));
- static void write_form_ilbm ARGS((int size));
- static void write_bmhd ARGS((int cols, int rows, int nPlanes));
- static void write_std_cmap ARGS((colorhist_vector chv, int colors, int maxval));
- static void encode_row ARGS((rawtype *row, int cols, int nPlanes));
- static int get_int_val ARGS((char *string, char *option, int bot, int top));
- static pixel * next_pixrow ARGS((FILE *fp, int row));
- static pixval * make_val_table ARGS((pixval oldmaxval, pixval newmaxval));
- static void * xmalloc ARGS((int bytes));
- static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int readall));
-
-
- static unsigned char *coded_rowbuf;
- static pixel **pixels;
- static pixel *pixrow;
-
- #define NEWDEPTH(pix, table) PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)])
-
- #define MAXCOLORS (1<<maxplanes)
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- FILE *ifp;
- int argn, rows, cols, colors, nPlanes;
- int ifmode, forcemode, maxplanes, fixplanes, hambits, mode;
- pixval maxval;
- colorhist_vector chv;
- DirectColor dcol;
- char *mapfile;
- char *usage =
- "[-ecs|-aga] [-ham6|-ham8] [-maxplanes|-mp n] [-fixplanes|-fp n] \
- [-normal|-hamif|-hamforce|-24if|-24force|-dcif|-dcforce|-cmaponly] \
- [-hambits|-hamplanes n] [-dcbits|-dcplanes r g b] \
- [-map ppmfile] [ppmfile]";
-
- ppm_init(&argc, argv);
-
- ifmode = MODE_NONE; forcemode = MODE_NONE;
- maxplanes = DEF_MAXPLANES; fixplanes = 0;
- hambits = DEF_HAMPLANES;
- mapfile = NULL;
- dcol.r = dcol.g = dcol.b = DEF_DCOLPLANES;
-
- argn = 1;
- while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
- if( pm_keymatch(argv[argn], "-maxplanes", 4) || pm_keymatch(argv[argn], "-mp", 3) ) {
- if( ++argn >= argc )
- pm_usage(usage);
- maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
- fixplanes = 0;
- }
- else
- if( pm_keymatch(argv[argn], "-fixplanes", 4) || pm_keymatch(argv[argn], "-fp", 3) ) {
- if( ++argn >= argc )
- pm_usage(usage);
- fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
- maxplanes = fixplanes;
- }
- else
- if( pm_keymatch(argv[argn], "-map", 4) ) {
- if( ++argn >= argc )
- pm_usage(usage);
- mapfile = argv[argn];
- }
- else
- if( pm_keymatch(argv[argn], "-cmaponly", 3) ) {
- forcemode = MODE_CMAP;
- }
- else
- if( pm_keymatch(argv[argn], "-hambits", 5) || pm_keymatch(argv[argn], "-hamplanes", 5) ) {
- if( ++argn > argc )
- pm_usage(usage);
- hambits = get_int_val(argv[argn], argv[argn-1], 3, MAXPLANES);
- }
- else
- if( pm_keymatch(argv[argn], "-ham6", 5) ) {
- hambits = ECS_HAMPLANES;
- forcemode = MODE_HAM;
- }
- else
- if( pm_keymatch(argv[argn], "-ham8", 5) ) {
- hambits = AGA_HAMPLANES;
- forcemode = MODE_HAM;
- }
- else
- if( pm_keymatch(argv[argn], "-ecs", 2) ) {
- maxplanes = ECS_MAXPLANES;
- hambits = ECS_HAMPLANES;
- }
- else
- if( pm_keymatch(argv[argn], "-aga", 2) ) {
- maxplanes = AGA_MAXPLANES;
- hambits = AGA_HAMPLANES;
- }
- else
- if( pm_keymatch(argv[argn], "-hamif", 5) )
- ifmode = MODE_HAM;
- else
- if( pm_keymatch(argv[argn], "-nohamif", 7) ) {
- if( ifmode == MODE_HAM )
- ifmode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-hamforce", 5) )
- forcemode = MODE_HAM;
- else
- if( pm_keymatch(argv[argn], "-nohamforce", 7) ) {
- if( forcemode == MODE_HAM )
- forcemode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-24if", 4) )
- ifmode = MODE_24;
- else
- if( pm_keymatch(argv[argn], "-no24if", 6) ) {
- if( ifmode == MODE_24 )
- ifmode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-24force", 4) )
- forcemode = MODE_24;
- else
- if( pm_keymatch(argv[argn], "-no24force", 6) ) {
- if( forcemode == MODE_24 )
- forcemode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-dcif", 4) ) {
- ifmode = MODE_DIRECT;
- }
- else
- if( pm_keymatch(argv[argn], "-nodcif", 6) ) {
- if( ifmode == MODE_DIRECT )
- ifmode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-dcforce", 4) ) {
- forcemode = MODE_DIRECT;
- }
- else
- if( pm_keymatch(argv[argn], "-nodcforce", 6) ) {
- if( forcemode == MODE_DIRECT )
- forcemode = MODE_NONE;
- }
- else
- if( pm_keymatch(argv[argn], "-dcbits", 4) || pm_keymatch(argv[argn], "-dcplanes", 4) ) {
- char *option = argv[argn];
-
- if( ++argn >= argc )
- pm_usage(usage);
- dcol.r = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
- if( ++argn >= argc )
- pm_usage(usage);
- dcol.g = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
- if( ++argn >= argc )
- pm_usage(usage);
- dcol.b = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
- }
- else
- if( pm_keymatch(argv[argn], "-normal", 4) )
- ifmode = forcemode = MODE_NONE;
- else
- pm_usage(usage);
- ++argn;
- }
-
- if( argn < argc ) {
- ifp = pm_openr(argv[argn]);
- ++argn;
- }
- else
- ifp = stdin;
-
- if( argn != argc )
- pm_usage( usage );
-
- if( forcemode != MODE_NONE && mapfile != NULL )
- pm_message("warning - mapfile only used for normal ILBMs");
-
- mode = forcemode;
- switch( forcemode ) {
- case MODE_HAM:
- /* grayscale colormap for now - we don't need to read the whole
- file into memory and can use row-by-row operation */
- init_read(ifp, &cols, &rows, &maxval, 0);
- pm_message("hamforce option used - proceeding to write a HAM%d file", hambits);
- break;
- case MODE_24:
- init_read(ifp, &cols, &rows, &maxval, 0);
- pm_message("24force option used - proceeding to write a 24bit file");
- break;
- case MODE_DIRECT:
- init_read(ifp, &cols, &rows, &maxval, 0);
- pm_message("dcforce option used - proceeding to write a %d:%d:%d direct color file",
- dcol.r, dcol.g, dcol.b);
- break;
- case MODE_CMAP:
- /* must read the whole file into memory */
- init_read(ifp, &cols, &rows, &maxval, 1);
-
- /* Figure out the colormap. */
- pm_message("computing colormap...");
- chv = ppm_computecolorhist(pixels, cols, rows, MAXCMAPCOLORS, &colors);
- if( chv == (colorhist_vector)NULL )
- pm_error("too many colors - try doing a 'ppmquant %d'", MAXCMAPCOLORS);
- pm_message("%d colors found", colors);
- break;
- default:
- /* must read the whole file into memory */
- init_read(ifp, &cols, &rows, &maxval, 1);
-
- /* Figure out the colormap. */
- if( mapfile ) {
- int mapcols, maprows, row, col;
- pixel **mappixels, *pP;
- pixval mapmaxval;
-
- pm_message("reading colormap file...");
- ifp = pm_openr(mapfile);
- mappixels = ppm_readppm(ifp, &mapcols, &maprows, &mapmaxval);
- pm_close(ifp);
- if( mapcols == 0 || maprows == 0 )
- pm_error("null colormap??");
-
- /* if the maxvals of the ppmfile and the mapfile are the same,
- * then the scaling to MAXCOLVAL (if necessary) will be done by
- * the write_std_cmap() function.
- * Otherwise scale them both to MAXCOLVAL.
- */
- if( maxval != mapmaxval ) {
- if( mapmaxval != MAXCOLVAL ) {
- pixval *table;
- pm_message("colormap maxval is not %d - rescaling colormap...", MAXCOLVAL);
- table = make_val_table(mapmaxval, MAXCOLVAL);
- for( row = 0; row < maprows; ++row )
- for( col = 0, pP = mappixels[row]; col < mapcols; ++col, ++pP )
- NEWDEPTH(*pP, table); /* was PPM_DEPTH( *pP, *pP, mapmaxval, MAXCOLVAL ); */
- mapmaxval = MAXCOLVAL;
- free(table);
- }
-
- if( maxval != mapmaxval ) {
- pixval *table;
- pm_message("rescaling colors of picture...");
- table = make_val_table(maxval, mapmaxval);
- for( row = 0; row < rows; ++row )
- for( col = 0, pP = pixels[row]; col < cols; ++col, ++pP )
- NEWDEPTH(*pP, table); /* was PPM_DEPTH( *pP, *pP, maxval, mapmaxval ); */
- maxval = mapmaxval;
- free(table);
- }
- }
-
- pm_message("computing colormap...");
- chv = ppm_computecolorhist(mappixels, mapcols, maprows, MAXCMAPCOLORS, &colors);
- ppm_freearray(mappixels, maprows);
- if( chv == (colorhist_vector)NULL )
- pm_error("too many colors in colormap!");
- pm_message("%d colors found in colormap", colors);
-
- nPlanes = fixplanes = maxplanes = colorstobpp(colors);
- }
- else {
- pm_message("computing colormap...");
- chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors);
- if( chv == (colorhist_vector)0 ) {
- /* too many colors */
- mode = ifmode;
- switch( ifmode ) {
- case MODE_HAM:
- pm_message("too many colors - proceeding to write a HAM%d file", hambits);
- pm_message("if you want a non-HAM file, try doing a 'ppmquant %d'", MAXCOLORS);
- break;
- case MODE_24:
- pm_message("too many colors - proceeding to write a 24bit file" );
- pm_message("if you want a non-24bit file, try doing a 'ppmquant %d'", MAXCOLORS);
- break;
- case MODE_DIRECT:
- pm_message("too many colors - proceeding to write a %d:%d:%d direct color file",
- dcol.r, dcol.g, dcol.b);
- pm_message("if you want a non-direct-color file, try doing a 'ppmquant %d'", MAXCOLORS);
- break;
- default:
- pm_message( "too many colors for %d planes", maxplanes );
- pm_message( "either use -hamif/-hamforce/-24if/-24force/-dcif/-dcforce/-maxplanes,");
- pm_error( "or try doing a 'ppmquant %d'", MAXCOLORS );
- break;
- }
- }
- else {
- pm_message("%d colors found", colors);
- nPlanes = colorstobpp(colors);
- if( fixplanes > nPlanes )
- nPlanes = fixplanes;
- }
- }
- break;
- }
-
- if( mode != MODE_CMAP )
- coded_rowbuf= (unsigned char *)xmalloc(RowBytes(cols));
-
- switch( mode ) {
- case MODE_HAM:
- ppm_to_ham(ifp, cols, rows, maxval, hambits);
- break;
- case MODE_24:
- ppm_to_24(ifp, cols, rows, maxval);
- break;
- case MODE_DIRECT:
- ppm_to_direct(ifp, cols, rows, maxval, &dcol);
- break;
- case MODE_CMAP:
- ppm_to_cmap(maxval, chv, colors);
- break;
- default:
- ppm_to_std(ifp, cols, rows, maxval, chv, colors, nPlanes);
- break;
- }
- pm_close(ifp);
- exit(0);
- }
-
-
- static void
- ppm_to_ham(fp, cols, rows, maxval, hambits)
- FILE *fp;
- int cols, rows, maxval, hambits;
- {
- int colors, colbits, nPlanes, formsize, cmapsize, i, hammaxval;
- pixel *pP;
- register int row, col;
- pixval *table = NULL;
- rawtype *raw_rowbuf;
-
- raw_rowbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
- colbits = hambits-2;
- colors = 1 << colbits;
- hammaxval = pm_bitstomaxval(colbits);
- nPlanes = hambits;
- cmapsize = colors * 3;
- if( odd(cmapsize) )
- cmapsize++; /* pad CMAP to a word */
-
- formsize =
- 4 + /* ILBM */
- 4 + 4 + 20 + /* BMHD size header */
- 4 + 4 + 4 + /* CAMG size val */
- 4 + 4 + cmapsize + /* CMAP size colormap */
- 4 + 4 + rows * nPlanes * RowBytes(cols); /* BODY size data */
-
- write_form_ilbm(formsize);
- write_bmhd(cols, rows, nPlanes);
-
- /* write camg */
- put_fourchars("CAMG");
- put_big_long(4);
- put_big_long(vmHAM);
-
- /* write grayscale colormap */
- put_fourchars("CMAP");
- put_big_long(colors * 3);
- table = make_val_table(hammaxval, MAXCOLVAL);
- for( i = 0; i < colors; i++ ) {
- put_byte( table[i] ); /* red */
- put_byte( table[i] ); /* green */
- put_byte( table[i] ); /* blue */
- }
- free(table); table = NULL;
- if( odd(colors * 3) )
- put_byte(0);
-
- /* write body */
- put_fourchars("BODY");
- put_big_long(rows * nPlanes * RowBytes(cols));
-
- if( hammaxval != maxval )
- table = make_val_table(maxval, hammaxval);
-
- for( row = 0; row < rows; row++ ) {
- register int noprev, pr, pg, pb, r, g, b, l;
-
- noprev = 1;
- for( col = 0, pP = next_pixrow(fp, row); col < cols; col++, pP++ ) {
- r = PPM_GETR( *pP );
- g = PPM_GETG( *pP );
- b = PPM_GETB( *pP );
- l = (int)(PPM_LUMIN(*pP) + 0.5); /* -IUW added '+ 0.5' */
- if( table ) {
- r = table[r];
- g = table[g];
- b = table[b];
- l = table[l];
- }
-
- if( noprev ) {
- /* No previous pixels, gotta use the gray option. */
- raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
- pr = pg = pb = l;
- noprev = 0;
- }
- else {
- register int dred, dgreen, dblue, dgray;
- /* Compute distances for the four options. */
- dred = abs( g - pg ) + abs( b - pb );
- dgreen = abs( r - pr ) + abs( b - pb );
- dblue = abs( r - pr ) + abs( g - pg );
- dgray = abs( r - l ) + abs( g - l ) + abs( b - l );
-
- if( dgray <= dred && dgray <= dgreen && dgray <= dblue ) { /* -IUW '<=' was '<' */
- raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
- pr = pg = pb = l;
- }
- else
- if( dblue <= dred && dblue <= dgreen ) {
- raw_rowbuf[col] = b + (HAMCODE_BLUE << colbits);
- pb = b;
- }
- else
- if( dred <= dgreen ) {
- raw_rowbuf[col] = r + (HAMCODE_RED << colbits);
- pr = r;
- }
- else {
- raw_rowbuf[col] = g + (HAMCODE_GREEN << colbits);
- pg = g;
- }
- }
- }
- encode_row(raw_rowbuf, cols, nPlanes);
- }
- if( table )
- free(table);
- free(raw_rowbuf);
- }
-
-
- static void
- ppm_to_24(fp, cols, rows, maxval)
- FILE *fp;
- int cols, rows, maxval;
- {
- int formsize, nPlanes;
- register int row, col;
- pixel *pP;
- pixval *table = NULL;
- rawtype *redbuf, *greenbuf, *bluebuf;
-
- redbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
- greenbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
- bluebuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
-
- nPlanes = 24;
-
- formsize =
- 4 + /* ILBM */
- 4 + 4 + 20 + /* BMHD size header */
- 4 + 4 + rows * nPlanes * RowBytes(cols); /* BODY size data */
-
- write_form_ilbm(formsize);
- write_bmhd(cols, rows, nPlanes);
-
- /* write body */
- put_fourchars("BODY");
- put_big_long(rows * nPlanes * RowBytes(cols));
-
- if( maxval != MAXCOLVAL ) {
- pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
- table = make_val_table(maxval, MAXCOLVAL);
- }
- for( row = 0; row < rows; row++ ) {
- pP = next_pixrow(fp, row);
- if( table ) {
- for( col = 0; col < cols; col++, pP++ ) {
- redbuf[col] = table[PPM_GETR(*pP)];
- greenbuf[col] = table[PPM_GETG(*pP)];
- bluebuf[col] = table[PPM_GETB(*pP)];
- }
- }
- else {
- for( col = 0; col < cols; col++, pP++ ) {
- redbuf[col] = PPM_GETR(*pP);
- greenbuf[col] = PPM_GETG(*pP);
- bluebuf[col] = PPM_GETB(*pP);
- }
- }
- encode_row(redbuf, cols, 8);
- encode_row(greenbuf, cols, 8);
- encode_row(bluebuf, cols, 8);
- }
- if( table )
- free(table);
- free(redbuf);
- free(greenbuf);
- free(bluebuf);
- }
-
-
- static void
- ppm_to_direct(fp, cols, rows, maxval, dcol)
- FILE *fp;
- int cols, rows, maxval;
- DirectColor *dcol;
- {
- int formsize, nPlanes;
- register int row, col;
- pixel *pP;
- pixval *redtable = NULL, *greentable = NULL, *bluetable = NULL;
- pixval redmaxval, greenmaxval, bluemaxval;
- rawtype *redbuf, *greenbuf, *bluebuf;
-
- redbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
- greenbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
- bluebuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
-
- nPlanes = dcol->r + dcol->g + dcol->b;
- redmaxval = pm_bitstomaxval(dcol->r);
- if( redmaxval != maxval ) {
- pm_message("rescaling reds to %d bits", dcol->r);
- redtable = make_val_table(maxval, redmaxval);
- }
- greenmaxval = pm_bitstomaxval(dcol->g);
- if( greenmaxval != maxval ) {
- pm_message("rescaling greens to %d bits", dcol->g);
- greentable = make_val_table(maxval, greenmaxval);
- }
- bluemaxval = pm_bitstomaxval(dcol->b);
- if( bluemaxval != maxval ) {
- pm_message("rescaling blues to %d bits", dcol->b);
- bluetable = make_val_table(maxval, bluemaxval);
- }
-
- formsize =
- 4 + /* ILBM */
- 4 + 4 + 20 + /* BMHD size header */
- 4 + 4 + 4 + /* DCOL size description */
- 4 + 4 + rows * nPlanes * RowBytes(cols); /* BODY size data */
-
- write_form_ilbm(formsize);
- write_bmhd(cols, rows, nPlanes);
-
- /* write DCOL */
- put_fourchars("DCOL");
- put_big_long(4);
- put_byte(dcol->r);
- put_byte(dcol->g);
- put_byte(dcol->b);
- put_byte(0); /* pad */
-
- /* write body */
- put_fourchars("BODY");
- put_big_long(rows * nPlanes * RowBytes(cols));
-
- for( row = 0; row < rows; row++ ) {
- pP = next_pixrow(fp, row);
- for( col = 0; col < cols; col++, pP++ ) {
- register pixval r, g, b;
-
- r = PPM_GETR(*pP); if( redtable ) r = redtable[r];
- g = PPM_GETG(*pP); if( greentable ) g = greentable[g];
- b = PPM_GETB(*pP); if( bluetable ) b = bluetable[b];
-
- redbuf[col] = r;
- greenbuf[col] = g;
- bluebuf[col] = b;
- }
- encode_row(redbuf, cols, dcol->r);
- encode_row(greenbuf, cols, dcol->g);
- encode_row(bluebuf, cols, dcol->b);
- }
- if( redtable )
- free(redtable);
- if( greentable )
- free(greentable);
- if( bluetable )
- free(bluetable);
- free(redbuf);
- free(greenbuf);
- free(bluebuf);
- }
-
-
- static void
- ppm_to_cmap(maxval, chv, colors)
- int maxval;
- colorhist_vector chv;
- int colors;
- {
- int formsize, cmapsize;
-
- cmapsize = colors * 3;
- if( odd(cmapsize) )
- cmapsize++; /* pad to a word */
-
- formsize =
- 4 + /* ILBM */
- 4 + 4 + 20 + /* BMHD size header */
- 4 + 4 + cmapsize; /* CMAP size colormap */
-
- write_form_ilbm(formsize);
- write_bmhd(0, 0, 0);
- write_std_cmap(chv, colors, maxval);
- }
-
-
- static void
- ppm_to_std(fp, cols, rows, maxval, chv, colors, nPlanes)
- FILE *fp;
- int cols, rows, maxval;
- colorhist_vector chv;
- int colors, nPlanes;
- {
- int formsize, cmapsize;
- colorhash_table cht;
- register int row, col;
- pixel *pP;
- rawtype *raw_rowbuf;
-
- raw_rowbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
-
- /* Make a hash table for fast color lookup. */
- cht = ppm_colorhisttocolorhash(chv, colors);
-
- cmapsize = colors * 3;
- if( odd(cmapsize) )
- cmapsize++; /* pad CMAP to a word */
-
- formsize =
- 4 + /* ILBM */
- 4 + 4 + 20 + /* BMHD size header */
- 4 + 4 + cmapsize + /* CMAP size colormap */
- 4 + 4 + rows * nPlanes * RowBytes(cols); /* BODY size data */
-
- write_form_ilbm(formsize);
- write_bmhd(cols, rows, nPlanes);
- write_std_cmap(chv, colors, maxval);
-
- /* write body */
- put_fourchars("BODY");
- put_big_long(rows * nPlanes * RowBytes(cols));
-
- for( row = 0; row < rows; row++ ) {
- for( col = 0, pP = next_pixrow(fp, row); col < cols; col++, pP++ ) {
- int ind;
-
- /* Check hash table to see if we have already matched this color. */
- ind = ppm_lookupcolor(cht, pP);
- if( ind == -1 ) {
- /* No; search colormap for closest match. */
- /* algorithm taken from ppmquant.c -IUW */
- register int i, r1, g1, b1, r2, g2, b2;
- register long dist, newdist;
-
- r1 = PPM_GETR(*pP);
- g1 = PPM_GETG(*pP);
- b1 = PPM_GETB(*pP);
- dist = 2000000000;
- for( i = 0; i < colors; ++i ) {
- r2 = PPM_GETR(chv[i].color);
- g2 = PPM_GETG(chv[i].color);
- b2 = PPM_GETB(chv[i].color);
- newdist = ( r1 - r2 ) * ( r1 - r2 ) +
- ( g1 - g2 ) * ( g1 - g2 ) +
- ( b1 - b2 ) * ( b1 - b2 );
- if( newdist < dist ) {
- ind = i;
- dist = newdist;
- }
- }
- }
- raw_rowbuf[col] = ind;
- }
- encode_row(raw_rowbuf, cols, nPlanes);
- }
- }
-
-
- static void
- write_std_cmap(chv, colors, maxval)
- colorhist_vector chv;
- int colors, maxval;
- {
- int cmapsize, i;
-
- cmapsize = 3 * colors;
-
- /* write colormap */
- put_fourchars("CMAP");
- put_big_long(cmapsize);
- if( maxval != MAXCOLVAL ) {
- pixval *table;
- pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
- table = make_val_table(maxval, MAXCOLVAL);
- for( i = 0; i < colors; i++ ) {
- put_byte((char)(table[PPM_GETR(chv[i].color)]));
- put_byte((char)(table[PPM_GETG(chv[i].color)]));
- put_byte((char)(table[PPM_GETB(chv[i].color)]));
- }
- free(table);
- }
- else {
- for( i = 0; i < colors; i++ ) {
- put_byte(PPM_GETR(chv[i].color));
- put_byte(PPM_GETG(chv[i].color));
- put_byte(PPM_GETB(chv[i].color));
- }
- }
- if( odd(cmapsize) )
- put_byte(0);
- }
-
-
- static void
- write_form_ilbm(size)
- int size;
- {
- put_fourchars("FORM");
- put_big_long(size);
- put_fourchars("ILBM");
- }
-
-
- static void
- write_bmhd(cols, rows, nPlanes)
- int cols, rows, nPlanes;
- {
- put_fourchars("BMHD");
- put_big_long(20);
-
- put_big_short(cols);
- put_big_short(rows);
- put_big_short(0); /* x */
- put_big_short(0); /* y */
- put_byte(nPlanes);
- put_byte(mskNone); /* masking type */
- put_byte(cmpNone); /* compression type */
- put_byte(0); /* pad1 */
- put_big_short(0); /* tranparentColor */
- put_byte(10); /* xAsp */
- put_byte(10); /* yAsp */
- put_big_short(cols); /* pageWidth */
- put_big_short(rows); /* pageHeight */
- }
-
-
- /* encode algorithm by Johan Widen (jw@jwdata.se) */
- const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
-
- static void
- encode_row(row, cols, nPlanes)
- rawtype *row;
- int cols, nPlanes;
- {
- register int plane, col;
- int bytes;
-
- bytes = RowBytes(cols);
-
- /* Encode and write raw bytes in plane-interleaved form. */
- for( plane = 0; plane < nPlanes; plane++ ) {
- int mask, cbit, wr;
- unsigned char *cp;
- rawtype *rp;
-
- mask = 1 << plane;
- cbit = -1;
- cp = coded_rowbuf-1;
- rp = row;
- for( col = 0; col < cols; col++, cbit--, rp++ ) {
- if( cbit < 0 ) {
- cbit = 7;
- *++cp = 0;
- }
- if( *rp & mask )
- *cp |= bit_mask[cbit];
- }
- wr = fwrite(coded_rowbuf, 1, bytes, stdout);
- if( wr != bytes )
- pm_error("write error");
- }
- }
-
-
- static int
- colorstobpp(colors)
- int colors;
- {
- int i;
-
- for( i = 1; i <= MAXPLANES; i++ ) {
- if( colors <= (1 << i) )
- return i;
- }
- pm_error("too many planes (max %d)", MAXPLANES);
- }
-
-
- #if 0
- static void
- put_fourchars(str)
- char* str;
- {
- fputs( str, stdout );
- }
- #endif
-
-
- static void
- put_big_short(s)
- short s;
- {
- if ( pm_writebigshort( stdout, s ) == -1 )
- pm_error( "write error" );
- }
-
-
- static void
- put_big_long(l)
- long l;
- {
- if ( pm_writebiglong( stdout, l ) == -1 )
- pm_error( "write error" );
- }
-
-
- #if 0
- static void
- put_byte(b)
- unsigned char b;
- {
- (void) putc( b, stdout );
- }
- #endif
-
-
- static int
- get_int_val(string, option, bot, top)
- char *string, *option;
- int bot, top;
- {
- int val;
-
- if( sscanf(string, "%d", &val) != 1 )
- pm_error("option \"%s\" needs integer argument", option);
-
- if( val < bot || val > top )
- pm_error("option \"%s\" argument value out of range (%d..%d)", option, bot, top);
-
- return val;
- }
-
-
-
-
- static pixval *
- make_val_table(oldmaxval, newmaxval)
- pixval oldmaxval, newmaxval;
- {
- int i;
- pixval *table;
-
- table = xmalloc((oldmaxval + 1) * sizeof(pixval));
- for(i = 0; i <= oldmaxval; i++ )
- table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
-
- return table;
- }
-
-
- static void *
- xmalloc(bytes)
- int bytes;
- {
- void *mem;
-
- mem = malloc(bytes);
- if( mem == NULL )
- pm_error("out of memory allocating %d bytes", bytes);
- return mem;
- }
-
-
- static int gFormat;
- static int gCols;
- static int gMaxval;
-
- static void
- init_read(fp, colsP, rowsP, maxvalP, readall)
- FILE *fp;
- int *colsP, *rowsP;
- pixval *maxvalP;
- int readall;
- {
- if( readall ) {
- pixels = ppm_readppm(fp, colsP, rowsP, maxvalP);
- }
- else {
- ppm_readppminit(fp, colsP, rowsP, maxvalP, &gFormat);
- pixrow = ppm_allocrow(*colsP);
- }
- gCols = *colsP;
- gMaxval = *maxvalP;
- }
-
-
- static pixel *
- next_pixrow(fp, row)
- FILE *fp;
- int row;
- {
- if( pixels )
- pixrow = pixels[row];
- else {
- static int rowcnt;
- if( row != rowcnt )
- pm_error("big mistake");
- rowcnt++;
- ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat);
- }
- return pixrow;
- }
-
-